/**
 * Copyright(c) 2013 Jade Techonologies Co., Ltd.
 *
 * History:
 *   13-4-14 下午5:51 Created by sky
 */
package com.jade.bss.base.customer.impl;

import java.util.*;
import javax.annotation.PostConstruct;
import javax.ejb.TransactionAttribute;
import javax.inject.Inject;
import javax.inject.Named;

import com.jade.bss.base.customer.*;
import com.jade.framework.base.criterion.Criteria;
import com.jade.framework.base.util.PagingArrayList;
import com.jade.framework.base.util.PagingList;
import com.jade.framework.base.util.encryption.Encryption;
import com.jade.framework.base.util.encryption.EncryptionUtils;
import com.jade.modules.region.RegionUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.transaction.annotation.Transactional;

/**
 * CustomerManager的基本实现。
 *
 * @author sky
 * @version 1.0 13-4-14 下午5:51
 */
@Named ("bss_customerManager")
public class CustomerManagerImpl
        implements CustomerManager
{
    protected CustomerDao customerDao;
    protected Encryption encryption = EncryptionUtils.getDefaultEncryption();
    protected boolean nameIgnoreCase = true;

    @PostConstruct
    public void init()
    {
    }

    public void setNameIgnoreCase(boolean nameIgnoreCase)
    {
        this.nameIgnoreCase = nameIgnoreCase;
    }

    @Inject
    public void setCustomerDao(@Named ("bss_customerDao") CustomerDao customerDao)
    {
        this.customerDao = customerDao;
    }

    public void setEncryption(String encryption)
    {
        this.encryption = EncryptionUtils.getEncryption(encryption);
    }

    protected String encryptPassword(String password)
    {
        if (password != null) {
            return encryption.encrypt(password);
        }
        else {
            return null;
        }
    }

    protected void encryptPassword(Customer customer)
    {
        if (encryption != null && StringUtils.isNotEmpty(customer.getPassword())) {
            String encPassword = encryptPassword(customer.getPassword());
            customer.setPassword(encPassword);
        }
    }

    protected void checkNameExist(Customer customer)
            throws CustomerException
    {
        Customer c = getCustomer(customer.getType(), customer.getName());
        if (c != null) {
            throw new CustomerException(CustomerConstants.ERR_CUSTOMER_EXISTED, c.getName());
        }
    }

    protected void setRegion(Customer customer)
    {
        if (StringUtils.isBlank(customer.getRegion())) {
            if (StringUtils.isNotBlank(customer.getCounty())) {
                customer.setRegion(customer.getCounty());
            }
            else if (StringUtils.isNotBlank(customer.getCity())) {
                customer.setRegion(customer.getCity());
            }
            else if (StringUtils.isNotBlank(customer.getProvince())) {
                customer.setRegion(customer.getProvince());
            }
            else if (StringUtils.isNotBlank(customer.getCountry())) {
                customer.setRegion(customer.getCountry());
            }
        }
        //处理地区
        if (StringUtils.isNotBlank(customer.getRegion())) {
            //设置了Region，那么省市都以这个为准
            String[] ids = RegionUtils.getIds(customer.getRegion());
            if (ids.length > 0) {
                customer.setCountry(ids[0]);
            }
            if (ids.length > 1) {
                customer.setProvince(ids[1]);
            }
            if (ids.length > 2) {
                customer.setCity(ids[2]);
            }
            if (ids.length > 3) {
                customer.setCounty(ids[3]);
            }
        }
    }

    protected void setUpdateRegion(Customer customer)
    {
        if (StringUtils.isNotBlank(customer.getCounty())) {
            customer.setRegion(customer.getCounty());
        }
        else if (StringUtils.isNotBlank(customer.getCity())) {
            customer.setRegion(customer.getCity());
        }
        else if (StringUtils.isNotBlank(customer.getProvince())) {
            customer.setRegion(customer.getProvince());
        }
        else if (StringUtils.isNotBlank(customer.getCountry())) {
            customer.setRegion(customer.getCountry());
        }
    }

    @TransactionAttribute
    @Transactional (rollbackFor = Exception.class)
    public long addCustomer(Customer customer)
            throws CustomerException
    {
        //转换成小写
        if (nameIgnoreCase) {
            customer.setName(customer.getName().toLowerCase());
        }
        //校验客户名称
        checkNameExist(customer);

        //set region info
        setRegion(customer);

        if (customer.getCreationDate() != null) {
            customer.setCreationDate(new Date());
        }
        encryptPassword(customer);
        customerDao.addCustomer(customer);

        Map<Class, CustomerInfo> infos = customer.getInfos();
        if (infos != null && !infos.isEmpty()) {
            Set<Class> keys = infos.keySet();
            for (Class key : keys) {
                CustomerInfo info = infos.get(key);
                info.setCustomerId(customer.getId());
                customerDao.addInfo(info);
            }
        }
        return customer.getId();
    }

    public Customer getCustomer(long id)
    {
        return customerDao.getCustomer(id);
    }

    public Customer loadCustomer(long id)
            throws CustomerException
    {
        Customer c = getCustomer(id);
        if (c == null) {
            throw new CustomerException(CustomerConstants.ERR_CUSTOMER_NOT_EXISTED, null, id);
        }
        return c;
    }

    public Customer getCustomer(String name)
    {
        return getCustomer(null, name);
    }

    public Customer getCustomer(String type, String name)
    {
        //不区分大小写,转换成小写
        if (nameIgnoreCase) {
            name = name.toLowerCase();
        }
        return customerDao.getCustomer(type, name);
    }

    protected Customer loadCustomer(String type, String name)
            throws CustomerException
    {
        Customer c = getCustomer(type, name);
        if (c == null) {
            throw new CustomerException(CustomerConstants.ERR_CUSTOMER_NOT_EXISTED, name);
        }
        return c;
    }

    @TransactionAttribute
    @Transactional (rollbackFor = Exception.class)
    public void updateCustomer(Customer customer)
            throws CustomerException
    {
        Customer oldCustomer = loadCustomer(customer.getId());
        String oldName = oldCustomer.getName();
        boolean nameChanged = !oldName.equals(customer.getName());
        if (nameChanged) {
            //校验客户名称
            checkNameExist(customer);
        }

        //处理地区
//        setRegion(customer);
        setUpdateRegion(customer);
        oldCustomer.setRegion(customer.getRegion());
        oldCustomer.setCountry(customer.getCountry());
        oldCustomer.setProvince(customer.getProvince());
        oldCustomer.setCity(customer.getCity());
        oldCustomer.setCounty(customer.getCounty());


        oldCustomer.setEmail(customer.getEmail());
        oldCustomer.setMobile(customer.getMobile());
        oldCustomer.setTrueName(customer.getTrueName());
        oldCustomer.setGender(customer.getGender());
        oldCustomer.setLevel(customer.getLevel());
        oldCustomer.setStatus(customer.getStatus());
        oldCustomer.setNickName(customer.getNickName());
        oldCustomer.setCategoryId(customer.getCategoryId());
        oldCustomer.setLogo(customer.getLogo());
        oldCustomer.setCreateType(customer.getCreateType());
        oldCustomer.setBirthday(customer.getBirthday());
        if (oldCustomer.getTags() != null) {
            oldCustomer.getTags().clear();
            if(customer.getTags()!=null)
                oldCustomer.getTags().addAll(customer.getTags());
        }
        else {
            oldCustomer.setTags(customer.getTags());
        }
        customerDao.updateCustomer(oldCustomer);

        // 更新 extend info
        Map<Class, CustomerInfo> infos = customer.getInfos();
        if (infos != null && !infos.isEmpty()) {
            Set<Class> keys = infos.keySet();
            for (Class key : keys) {
                CustomerInfo info = infos.get(key);
                info.setCustomerId(customer.getId());
                customerDao.updateInfo(info);
            }
        }
    }

    @TransactionAttribute
    @Transactional (rollbackFor = Exception.class)
    public void updateStatus(int status, long... ids)
            throws CustomerException
    {
        for (long id : ids) {
            Customer customer = loadCustomer(id);
            customer.setStatus(status);
            customerDao.updateCustomer(customer);
        }
    }

    public Customer validateCustomer(String type, String name, String password)
            throws CustomerException
    {
        Customer c = loadCustomer(type, name);
        if (!validatePassword(c.getPassword(), password)) {
            throw new CustomerException(CustomerConstants.ERR_PASSWORD_NOT_MACHED, null);
        }
        return c;
    }

    public Customer validateCustomer(String name, String password)
            throws CustomerException
    {
        return validateCustomer(null, name, password);
    }

    public boolean validatePassword(String encPassword, String password)
    {
        String newEncPassword = encryptPassword(password);
        return !((newEncPassword != null && !newEncPassword.equals(encPassword)) ||
                (newEncPassword == null && encPassword != null));
    }

    @TransactionAttribute
    @Transactional (rollbackFor = Exception.class)
    public void modifyPassword(long id, String oldPassword, String newPassword)
            throws CustomerException
    {
        Customer c = loadCustomer(id);
        if (!validatePassword(c.getPassword(), oldPassword)) {
            throw new CustomerException(CustomerConstants.ERR_PASSWORD_NOT_MACHED, null);
        }
        c.setPassword(encryptPassword(newPassword));
        c.setPassFlag(Customer.PASSFLAG_USER);
        customerDao.updateCustomer(c);
    }

    protected PagingList<Customer> getCustomerInfo(PagingList<Customer> customers, Class... infoClasses)
    {
        List<Customer> customerList = new ArrayList<Customer>(customers.size());
        for (Customer customer : customers) {
            customer.setInfos(getExtendedInfos(customer.getId(), infoClasses));
            customerList.add(customer);
        }
        return new PagingArrayList<Customer>(customers.getTotalCount(), customerList);
    }

    public long getCustomerCountByType(String type)
    {
        return customerDao.getCustomerCountByType(type);
    }

    public PagingList<Customer> queryCustomer(Criteria criteria)
    {
        return customerDao.queryCustomer(criteria);
    }

    public PagingList<Customer> queryCustomer(Criteria criteria, Class... infoClasses)
    {
        PagingList<Customer> customers = customerDao.queryCustomer(criteria, infoClasses);
        return getCustomerInfo(customers, infoClasses);
    }



    public PagingList<Customer> querySortDistance(double lat, double lng, double distance, Criteria criteria,
                                                  Class... infoClasses)
    {
        PagingList<Customer> customers = customerDao.querySortDistance(lat, lng, distance, criteria, infoClasses);
        return getCustomerInfo(customers, infoClasses);
    }

    @TransactionAttribute
    @Transactional (rollbackFor = Exception.class)
    public void resetPassword(long id, String password)
            throws CustomerException
    {
        Customer customer = customerDao.getCustomer(id);
        customer.setPassword(encryptPassword(password));//是加密的
        customer.setPassFlag(Customer.PASSFLAG_RESET);
        customerDao.updateCustomer(customer);
    }

    @TransactionAttribute
    @Transactional (rollbackFor = Exception.class)
    public void removeCustomer(long... ids)
            throws CustomerException
    {
        for (long id : ids) {
            Customer customer = getCustomer(id);
            if (customer == null) {
                throw new CustomerException(CustomerConstants.ERR_CUSTOMER_EXISTED, null, id);
            }

            customerDao.removeCustomer(customer);
        }
    }

    @SuppressWarnings (value = "unchecked")
    public <Info extends CustomerInfo> Info getExtendedInfo(long customerId, Class infoClass)
    {
        return (Info) customerDao.getInfo(customerId, infoClass);
    }

    public Map<Class, CustomerInfo> getExtendedInfos(long customerId, Class... infoClasses)
    {
        Map<Class, CustomerInfo> infoMap = new HashMap<Class, CustomerInfo>();
        for (Class infoClass : infoClasses) {
            CustomerInfo info = getExtendedInfo(customerId, infoClass);
            infoMap.put(infoClass, info);
        }
        return infoMap;
    }

    @TransactionAttribute
    @Transactional (rollbackFor = Exception.class)
    public void updateExtendedInfo(CustomerInfo... infos)
            throws CustomerException
    {
        for (CustomerInfo info : infos) {
            customerDao.updateInfo(info);
        }
    }

    public void removeExtendedInfos(long customerId, Class... infoClasses)
            throws CustomerException
    {
        for (Class infoClass : infoClasses) {
            CustomerInfo info = customerDao.getInfo(customerId, infoClass);
            if (null != info) {
                customerDao.removeInfo(info);
            }
        }
    }

//    public List<String> listTopTag(int length)
//    {
//        return customerDao.listTopTag(length);
//    }

    public List<String> listTopTag(Criteria criteria)
    {
        return customerDao.listTopTag(criteria);
    }

    public long getUserCount(Date beginDate, Date endDate, String type)
    {
        return customerDao.getUserCount(beginDate,endDate,type);
    }
}
